home *** CD-ROM | disk | FTP | other *** search
/ L' Effet Pommier 3 / L'Effet Pommier - Volume 03.iso / Programmation / Alpha ƒ / Tcl / SystemCode / MacPerl.tcl < prev    next >
Text File  |  1996-01-02  |  47KB  |  1,593 lines

  1. #############################################################################
  2. # MacPerl.tcl
  3. # -----------
  4. #
  5. # This is a set of routines that allow Alpha to act as a front end for the
  6. # standalone MacPerl application and that allow Perl scripts to be used as 
  7. # text filters in Alpha.  These functions are accessed through a special 
  8. # MacPerl menu.
  9. #
  10. # The features of this package are explained in the file "MacPerl Help",
  11. # accessible from the Help menu.
  12. #
  13. #############################################################################
  14. #
  15. # If you don't already have MacPerl, it's available by anonymous ftp from
  16. # the umich site
  17. #
  18. #   mac.archive.umich.edu    [141.211.165.34]    mac/development/languages
  19. #
  20. # and its mirrors.  Also, MacPerl's home site is 
  21. #
  22. #   ftp.switch.ch            [130.59.1.40]        software/mac/src/mpw_c
  23. #
  24. # MacPerl was written (ported to the Mac) by 
  25. #        Matthias Neeracher <neeri@iis.ee.ethz.ch> , and
  26. #        Tim Endres <time@ice.com>.
  27. #
  28. #############################################################################
  29. # Author: W. Thomas Pollard <pollard@chem.columbia.edu>
  30. #
  31. # Version History:
  32. #
  33. # 2.51 1/96  -  Fixed problem w/ "Tell MacPerl:Save As..."
  34. # 2.5  1/96  -  Colorization and cmd-dbl-click modified to support Perl 5 docs
  35. # 2.41 7/95  -  Minor tweaks
  36. # 2.4  7/95  -  Fixed bugs affecting running unsaved scripts and error handling
  37. # 2.3  7/95  -  Minor tweaks and code rearrangement.
  38. # 2.2  6/95  -  Text filters act only on current line if "Apply to Buffer" is
  39. #                  false and no text has been selected.
  40. #               Bug fix in error-marking for scripts sent as AppleEvent params.
  41. #               Cmd-dbl-clicking a function call jumps to function, if
  42. #                  defined in the same file.
  43. # 2.1  6/95  -  Cmd-dbl-clicking a 'require'd filename opens the file.
  44. # 2.0  6/95  -  Minor bug fixes (incl. keyword decapitalization)
  45. #               Alpha 6.0b17 compatibility updates.
  46. #               Text Filters folder is settable from the App Paths menu now.
  47. # 1.9  5/95  -  Cmd-dbl-clicking Perl keywords and special variables displays
  48. #                  the man page info.
  49. # 1.81 4/95  -  one very minor Alpha compatibility update (winInfo->getWinInfo).
  50. # 1.8  4/95  -  Menu reorganized somewhat.
  51. #               Text Filters folder can now be anywhere.
  52. #               "ApplyToBuffer" flag ignored if text has been selected.
  53. #               Bug fixes.
  54. # 1.7  1/95  -  Updated to take advantage of MacPerl 4.1.4 AppleEvent features:
  55. #                1) Text filters use 'batch' doScript (.: STDOUT file obsolete)
  56. #                2) Filter scripts sent as doScript params (.: SCRIPT file obsolete)
  57. #                3) "Save As Droplet" and "Save as Runtime" commands added.
  58. #               Errors generated in 'require'd files are now displayed correctly
  59. # 1.6 10/94  -  "UseDebugger" flag added (forces scripts to run under debugger).
  60. #               Key bindings added for some menu commands.
  61. #               "perlDoScript{,2,3}" procs consolidated into a single proc.
  62. #               "saveAndRun" option added.
  63. #               Command-line args now parsed into units more correctly, in
  64. #                   particular, quoted file names aren't broken up.
  65. #               "Close Output Window" added to "Tell MacPerl" menu.
  66. #               Updated for Alpha 5.98 to load when menu is inserted.
  67. #               The error messages window is now recycled.
  68. #               "perlRecycleOutput" recycles output window.
  69. #               Minor bug fixes.
  70. # 1.5  9/94  -  MacPerl menu rearranged somewhat.
  71. #               Explicit "Get Output Window" command added to menu.
  72. #               Reading "#!" line for args is incompatible w/ standard,
  73. #                   so it's been dropped.
  74. #               Only scan the first 40 output lines for error messages (faster)
  75. #                "wrapFilterScript" no longer opens STDIN
  76. #               Text filters may now use command-line args
  77. #               STDIN for text filters passed as explicit cmd-line arg 
  78. # 1.4  9/94  -  The "#!" line of every script is read for command-line args,
  79. #                    which are passed explicitly to MacPerl with the script.
  80. #                "PromptForArgs" menu flag added.
  81. #                "perlCmdlineArgs" modeVar holds default command-line args.
  82. #                Scripts are sent using custom "perlDoScript2" proc, which
  83. #                    allows passing of explicit command-line args.
  84. # 1.3  9/94  -  When any script generates a compilation error, the file 
  85. #                    containing the script is brought up with the offending 
  86. #                    line highlighted; all error output is also written to
  87. #                    a "Perl Error Messages" window.
  88. #                'repeatLastFilter' runs again the last text-filter script used.
  89. #                'perlLastFilter' modeVar holds pathname of last filter.
  90. #                Menu flags now mirrored as modeVars, so they can be saved and
  91. #                    restored between sessions.
  92. #                Minor bug fixes.
  93. # 1.2  8/94  -  'retrieveOutput' and 'autoSwitch' flags added.
  94. #                'openInMacperl' added.
  95. #                MacPerl output window now closed before new scripts are sent.
  96. #                Filters now abort if there are compilation errors, and
  97. #                MacPerl diagnostic output retrieved and displayed in Alpha.
  98. # 1.1  8/94  -  'quitMacperl' added.
  99. #               perl-mode file-marking updated for Alpha 5.90
  100. #               Simplified installation via 'loadMacperl'(Pete Keleher). 
  101. # 1.0  7/94  -  perl-mode setup updated for Alpha 5.85:
  102. #                    keyword colorization supported
  103. #                    custom file-marking added
  104. #               #! lines in filter scripts now handled correctly 
  105. #               Workarounds installed for AppleEvent bug in MacPerl 4.1.3
  106. # 0.9  3/94  -  perl-mode stuff added, and
  107. #               highlighted 'Perl commands' file (man page) prepared
  108. #               minor bug fixes, too
  109. # 0.8  3/94  -  flags are now check-marked
  110. # 0.7  3/94  -  nested Text Filters folder now supported
  111. #               menu format modified somewhat
  112. # 0.6  3/94  -  'applyToBuffer' flag added
  113. #               scripts in Alpha buffers can now be used as filters 
  114. # 0.5  2/94  -  'filters', 'open special' submenu added
  115. #               'overwrite' flag added
  116. # 0.2  1/94  -  menu support added (Martijn Koster <m.koster@nexor.co.uk>)
  117. #               'execute selection', 'execute buffer' commands added
  118. # 0.1  9/93  -  text filter functionality created
  119. #                  
  120. ##############################################################################
  121. #
  122. proc dummyPerl {} {
  123. }
  124.  
  125. #############################################################################
  126. #  Default settings for the Perl menu flags  
  127. #
  128. set perlDefault(perlUseDebug) 0
  129. set perlDefault(perlGetOutput) 1
  130. set perlDefault(perlAutoSwitch) 1
  131. set perlDefault(perlOverwrite) 0
  132. set perlDefault(perlUsebuffer) 1
  133. set perlDefault(perlPromptArgs) 0
  134. set perlDefault(perlRecycleOutput) 0
  135. set perlDefault(perlPrevScript) {*startup*}
  136. set perlDefault(perlCmdlineArgs) {}
  137. set perlDefault(perlVersion) {4}
  138.  
  139. if {![info exists perlFilterPath]} {
  140.     set perlFilterPath "$HOME:Tcl:UserCode:Text Filters:"
  141. }
  142.  
  143. ##NEW
  144. if {![info exists perlDocs]} {
  145.     set perlDocs "$HOME:Help:Perl Commands"
  146. }
  147. ##
  148.  
  149. foreach var [array names perlDefault] {
  150.     if (![info exists PerlmodeVars($var)]) { 
  151.         set $var $perlDefault($var) 
  152.     } else {
  153.         set $var $PerlmodeVars($var) 
  154.     }
  155. }
  156. unset perlDefault
  157.  
  158. ##############################################################################
  159. # Make duplicate copies of these variables as modeVars, taking responsibility
  160. # for keeping the two sets consistent (argh!)
  161. #
  162. # (Maybe it's OK now to let them _just_ be modeVars, and not also ordinary
  163. # variables?)
  164. #
  165.  
  166. newModeVar Perl perlUseDebug $perlUseDebug 1
  167. newModeVar Perl perlGetOutput $perlGetOutput 1
  168. newModeVar Perl perlAutoSwitch $perlAutoSwitch 1
  169. newModeVar Perl perlOverwrite $perlOverwrite 1
  170. newModeVar Perl perlUsebuffer $perlUsebuffer 1
  171. newModeVar Perl perlPromptArgs $perlPromptArgs 1
  172. newModeVar Perl perlRecycleOutput $perlRecycleOutput 1
  173.  
  174. newModeVar Perl perlLastFilter $perlPrevScript 0
  175. newModeVar Perl perlCmdlineArgs $perlCmdlineArgs 0
  176.  
  177. ##############################################################################
  178. # Other Perl-mode variable definitions
  179. #
  180. newModeVar Perl elecRBrace    {0} 1
  181. newModeVar Perl elecLBrace    {1} 1
  182. newModeVar Perl electricSemi    {0} 1
  183. newModeVar Perl electricTab    {1} 1
  184. newModeVar Perl wordBreak        {(\$)?[a-zA-Z0-9_]+} 0
  185. newModeVar Perl prefixString    {# } 0
  186. newModeVar Perl wordWrap        {0} 1
  187. newModeVar Perl funcExpr        {^sub *([+-a-zA-Z0-9]+)} 0
  188. newModeVar Perl wordBreakPreface        {[^a-zA-Z0-9_\$]} 0
  189. newModeVar Perl autoMark    1    1
  190.  
  191. newModeVar Perl perlVersion $perlVersion 0
  192.  
  193. ##############################################################################
  194. # Miscellaneous definitions
  195. #
  196. set perlErrorWindow {* Perl Error Messages *}
  197. set perlOutputWindow {* Perl Output *}
  198.  
  199. set perlFilterMenu "textFilters"
  200.  
  201. set modeCode ":Tcl:SystemCode:Perl${perlVersion}Mode.tcl"
  202. if {[catch {source $HOME$modeCode}]} {
  203.     alertnote "Couldn't load the Perl-mode colorization file \"$modeCode\".  Contact the maintainer."
  204. }
  205.  
  206. #############################################################################
  207. #  Return paths to standard files, based on the path to MacPerl:
  208. #
  209. proc macperlFolder {} {
  210.    global macperlPath
  211.    regexp {(.*):([^:]*)} $macperlPath pathname dirname filename
  212.    return ${dirname}:
  213. }
  214.  
  215. proc stdinPath {} {
  216.    return [macperlFolder]STDIN
  217. }
  218.  
  219. proc scriptPath {} {
  220.    return [macperlFolder]SCRIPT
  221. }
  222.  
  223. #############################################################################
  224. # Define the dummy proc that will be called when the perl menu
  225. # is first inserted into the menubar
  226. #
  227. proc perlMenu {} {}
  228.  
  229. #############################################################################
  230. #  Build the perl menu
  231. #            
  232. set perlMenu "Ñ132"
  233. set perlOptsMenu "generalOptions"
  234. set filtOptsMenu "filterOptions"
  235.  
  236. menu -n $perlMenu [ concat {
  237.         "/'<Umacperl"
  238.         {menu -m -n "tellMacperl..." -p perlTellProc {
  239.            "/O<UOpen This File"
  240.            "Save As Droplet"
  241.            "Save As Runtime"
  242.            "Save As CGI"
  243.             "(-"
  244.            "Get Output Window"
  245.            "Close Output Window"
  246.            "Quit"
  247.            }
  248.         } 
  249.         "(-"
  250.         "runTheSelection"
  251.         "/R<UrunTheBuffer"
  252.         "/R<B<OsaveAndRun"
  253.         "runAFile"
  254.         "(-"
  255.     } [list [list menu -n $perlFilterMenu {}]] {
  256.        "selectBufferAsFilter"
  257.        "selectFileAsFilter"
  258.        "/F<UrepeatLastFilter"
  259.        "(-" 
  260.     } [list [list menu -n $perlOptsMenu {}]] {
  261.     } [list [list menu -n $filtOptsMenu {}]] {
  262.     } ]
  263.  
  264. enableMenuItem $perlMenu perlDebugWindow 0
  265. enableMenuItem "tellMacperl..." "Save As CGI" 0
  266.  
  267. if {$perlPrevScript == {} || $perlPrevScript == {*startup*}} {
  268.     enableMenuItem $perlMenu repeatLastFilter 0
  269. }
  270.  
  271. # General Perl-menu options menu
  272. #
  273. menu -n $perlOptsMenu {
  274.     "retrieveOutput"
  275.     "autoSwitch"
  276.     "promptForArgs"
  277.     "useDebugger"
  278.     }    
  279. markMenuItem $perlOptsMenu useDebugger $perlUseDebug
  280. markMenuItem $perlOptsMenu retrieveOutput $perlGetOutput
  281. markMenuItem $perlOptsMenu autoSwitch $perlAutoSwitch
  282. markMenuItem $perlOptsMenu promptForArgs $perlPromptArgs
  283.  
  284. # Text Filter options menu
  285. #
  286. menu -n $filtOptsMenu {
  287.     "applyToBuffer"
  288.     "overwriteSelection"
  289.     "(-"
  290.     "textFiltersFolder"
  291.     "rebuildFilterMenu"
  292.     }    
  293. markMenuItem $filtOptsMenu overwriteSelection $perlOverwrite
  294. markMenuItem $filtOptsMenu applyToBuffer $perlUsebuffer
  295.  
  296. # if ([info exists macperlPath]) {
  297. #     rebuildPerlMenu
  298. # }
  299.  
  300. #############################################################################
  301. #  Build a submenu of "preattached" Perl filters using the names of the 
  302. #  scripts in the Text Filters directory.  Called whenever Text Filters
  303. # folder is reassigned.
  304. #
  305. proc rebuildFilterMenu {{args}} {
  306.     global perlFilters perlFilterMenu perlFilterPath
  307.     global $perlFilterMenu
  308.     
  309.     eval [buildSubMenu $perlFilterPath $perlFilterMenu textFiltersProc perlFilters]
  310. }
  311.  
  312. rebuildFilterMenu
  313.  
  314. #############################################################################
  315. # Use variable tracing to keep global vars and modeVars consistent.
  316. #
  317. trace variable PerlmodeVars(perlUseDebug) w shadowPerl
  318. trace variable PerlmodeVars(perlOverwrite) w shadowPerl
  319. trace variable PerlmodeVars(perlUsebuffer) w shadowPerl
  320. trace variable PerlmodeVars(perlGetOutput) w shadowPerl
  321. trace variable PerlmodeVars(perlAutoSwitch) w shadowPerl
  322. trace variable PerlmodeVars(perlPromptArgs) w shadowPerl
  323. trace variable PerlmodeVars(perlLastFilter) w shadowPerl
  324. trace variable PerlmodeVars(perlCmdlineArgs) w shadowPerl
  325. trace variable PerlmodeVars(perlRecycleOutput) w shadowPerl
  326. trace variable PerlmodeVars(perlVersion) w shadowPerl
  327.  
  328. # perlFilterPath is now just a regular variable, set from the App Paths submenu
  329. trace variable perlFilterPath w rebuildFilterMenu
  330.  
  331. # ShadowPerl sets the global vars when the mode vars are modified and
  332. # keeps the menu checkmarked correctly.
  333. #
  334. proc shadowPerl {name1 name2 op} {
  335.     global HOME perlMenu perlOptsMenu filtOptsMenu
  336.     global perlOverwrite perlUsebuffer perlGetOutput perlAutoSwitch
  337.     global perlPromptArgs perlPrevScript perlCmdlineArgs perlUseDebug
  338.     global PerlmodeVars
  339.     if {$name1 == "PerlmodeVars" && $op == "w"} {
  340.         switch $name2 {
  341.             "perlUseDebug"    {
  342.                 set perlUseDebug $PerlmodeVars(perlUseDebug)
  343.                 markMenuItem $perlOptsMenu useDebugger $perlUseDebug
  344.              }
  345.             "perlOverwrite"    {
  346.                 set perlOverwrite $PerlmodeVars(perlOverwrite)
  347.                 markMenuItem $filtOptsMenu overwriteSelection $perlOverwrite
  348.              }
  349.             "perlUsebuffer"    {
  350.                 set perlUsebuffer $PerlmodeVars(perlUsebuffer)
  351.                 markMenuItem $filtOptsMenu applyToBuffer $perlUsebuffer
  352.              }
  353.             "perlGetOutput"    {
  354.                 set perlGetOutput $PerlmodeVars(perlGetOutput)
  355.                 markMenuItem $perlOptsMenu retrieveOutput $perlGetOutput 
  356.             }
  357.             "perlAutoSwitch" {    
  358.                 set perlAutoSwitch $PerlmodeVars(perlAutoSwitch)
  359.                 markMenuItem $perlOptsMenu autoSwitch $perlAutoSwitch 
  360.             }
  361.             "perlPromptArgs" {    
  362.                 set perlPromptArgs $PerlmodeVars(perlPromptArgs)
  363.                 markMenuItem $perlOptsMenu promptForArgs $perlPromptArgs 
  364.             }
  365.             "perlCmdlineArgs" {    
  366.                 set perlCmdlineArgs $PerlmodeVars(perlCmdlineArgs)
  367.             }
  368.             "perlRecycleOutput" {    
  369.                 set perlRecycleOutput $PerlmodeVars(perlRecycleOutput)
  370.             }
  371.             "perlVersion" {    
  372.                 set perlVersion $PerlmodeVars(perlVersion)
  373.                 set modeCode ":Tcl:SystemCode:Perl${perlVersion}Mode.tcl"
  374.                 if {[catch {source $HOME$modeCode}]} {
  375.                     alertnote "Couldn't load the Perl-mode colorization file \"$modeCode\".  Contact the maintainer."
  376.                 }
  377.             }
  378.             "perlLastFilter" {    
  379.                 # Don't allow perlPrevScript to be changed from the flags menu
  380.                 if {$perlPrevScript == "*startup*"} {
  381.                     set perlPrevScript $PerlmodeVars(perlLastFilter)
  382.                     enableMenuItem $perlMenu repeatLastFilter 1
  383.                 } else {
  384.                     set PerlmodeVars(perlLastFilter) $perlPrevScript 
  385.                 }
  386.             }
  387.             default {
  388.                 return
  389.             }
  390.         }
  391.     }
  392. }
  393.  
  394. #############################################################################
  395. # Menu commands
  396. #############################################################################
  397.  
  398. ############################################################################
  399. # Toggle the perl menu flags
  400. #
  401. proc retrieveOutput {} {
  402.     global perlMenu PerlmodeVars perlGetOutput modifiedModeVars
  403.     lappend modifiedModeVars [list perlGetOutput PerlmodeVars]
  404.     if {$perlGetOutput} then {
  405.         set PerlmodeVars(perlGetOutput) 0
  406.     } else {
  407.         set PerlmodeVars(perlGetOutput) 1
  408.     }
  409. }
  410.  
  411. proc useDebugger {} {
  412.     global perlMenu PerlmodeVars perlUseDebug modifiedModeVars
  413.     lappend modifiedModeVars [list  perlUseDebug PerlmodeVars]
  414.     if {$perlUseDebug} then {
  415.         set PerlmodeVars(perlUseDebug) 0
  416.     } else {
  417.         set PerlmodeVars(perlUseDebug) 1
  418.     }
  419. }
  420.  
  421. proc autoSwitch {} {
  422.     global perlMenu PerlmodeVars perlAutoSwitch modifiedModeVars
  423.     lappend modifiedModeVars [list  perlAutoSwitch PerlmodeVars]
  424.     if {$perlAutoSwitch} then {
  425.         set PerlmodeVars(perlAutoSwitch) 0
  426.     } else {
  427.         set PerlmodeVars(perlAutoSwitch) 1
  428.     }
  429. }
  430.  
  431. proc overwriteSelection {} {
  432.     global perlMenu perlOverwrite PerlmodeVars modifiedModeVars
  433.     lappend modifiedModeVars [list  perlOverwrite PerlmodeVars]
  434.     if {$perlOverwrite} then {
  435.         set PerlmodeVars(perlOverwrite) 0
  436.     } else {
  437.         set PerlmodeVars(perlOverwrite) 1
  438.     }
  439. }
  440.  
  441. proc applyToBuffer {} {
  442.     global perlMenu perlUsebuffer PerlmodeVars modifiedModeVars
  443.     lappend modifiedModeVars [list  perlUsebuffer PerlmodeVars]
  444.     if {$perlUsebuffer} then {
  445.            set PerlmodeVars(perlUsebuffer) 0
  446.     } else {
  447.            set PerlmodeVars(perlUsebuffer) 1
  448.     }
  449. }
  450.  
  451. proc promptForArgs {} {
  452.     global perlMenu perlPromptArgs PerlmodeVars modifiedModeVars
  453.     lappend modifiedModeVars [list perlPromptArgs PerlmodeVars]
  454.     if {$perlPromptArgs} then {
  455.            set PerlmodeVars(perlPromptArgs) 0
  456.     } else {
  457.            set PerlmodeVars(perlPromptArgs) 1
  458.     }
  459. }
  460.  
  461. proc textFiltersFolder {} {
  462.     global perlMenu perlFilterPath PerlmodeVars modifiedModeVars pathComments
  463.     
  464.     pathProc {} $pathComments(perlFilterPath)
  465. }
  466.  
  467. #############################################################################
  468. # Switch to MacPerl:
  469. proc macperl {} {
  470.     global macperlPath
  471.     set name [checkRunning MacPerl McPL macperlPath 0]
  472.     if {[string length $name]} {
  473.         switchTo "MacPerl"
  474.     } else {
  475.         alertnote "Couldn't run MacPerl"
  476.     }
  477. }
  478.  
  479. #############################################################################
  480. # Interact with MacPerl in some other way besides executing a script
  481. #
  482. proc perlTellProc {menu name} {
  483.     switch -exact $name {
  484.     "Open This File"        { openInMacperl }
  485.     
  486.     "Save As Droplet"        { saveThruMacperl "droplet" }
  487.     
  488.     "Save As Runtime"        { saveThruMacperl "runtime" }
  489.     
  490.     "Save As CGI"            { saveThruMacperl "cgi" }
  491.     
  492.     "Save As CGI-not"        { saveThruMacperl "cgi-not" }
  493.     
  494.     "Get Output Window"        { openPerlOutput }
  495.     
  496.     "Close Output Window"    { sendCloseWinName MacPerl MacPerl ;
  497.                               sendCloseWinName MacPerl "Perl Debug" }
  498.                             
  499.     "Quit"                    { quitMacperl }
  500.     }
  501. }
  502.  
  503. #############################################################################
  504. # Open the current file under MacPerl.  This used to useful for saving files 
  505. # as droplets or runtime scripts.  Maybe it's still useful for something...?
  506. #
  507. proc openInMacperl {} {
  508.     global macperlPath
  509.     set name [checkRunning MacPerl McPL macperlPath 0]
  510.     if {![string length $name]} {
  511.         alertnote "Couldn't run MacPerl"
  512.     }
  513.  
  514.     if {[winDirty]} {
  515.         case [askyesno -c "Save '[lindex [winNames] 0]'?"] in {
  516.             "yes" {save}
  517.             "no" {}
  518.             "cancel" {return}
  519.         }
  520.     }
  521.     switchTo $name
  522.     sendOpenEvent -n $name [lindex [winNames -f] 0]
  523. }
  524.  
  525. #############################################################################
  526. # Save the script in the current window as a MacPerl droplet or 
  527. # runtime script.  
  528. #
  529. proc saveThruMacperl {type} {
  530.     global macperlPath ALPHA
  531.     set name [checkRunning MacPerl McPL macperlPath 0]
  532.     if {![string length $name]} {
  533.         alertnote "Couldn't run MacPerl"
  534.     }
  535.     
  536.     getWinInfo arr
  537.     if {$arr(dirty) == 1} {
  538.         case [askyesno -c "Save '[lindex [winNames] 0]' source file also?"] in {
  539.             "yes" {save}
  540.             "no" {}
  541.             "cancel" {return}
  542.         }
  543.     }
  544.  
  545.     set destfile [AEFilename [putfile {Save droplet as} [lindex [winNames] 0]]]
  546.  
  547.     set script [curlyq [getText 0 [maxPos]]]
  548.  
  549.     if {$type == "droplet"} {
  550.         set saveType "SCPT"
  551.     } elseif {$type == "runtime"} {
  552.         set saveType "MrP7"
  553.     } elseif {$type == "cgi"} {
  554.         set saveType "WWW╜"
  555.     } elseif {$type == "cgi-not"} {
  556.         set saveType "WWWO"
  557.     } elseif {$type == "text"} {
  558.         set saveType "TEXT"
  559.     }
  560.     
  561.     set err [catch {eval "AEBuild -t 36000 -r \"$name\"" core save {----} [list $script] {dest:} [list $destfile] {fltp:} $saveType } reply ]
  562.     if {$err} { message "AEBuild error code $err in saveThruMacperl" }
  563.     
  564. # The following lines could be used to tell MacPerl to take the script file 
  565. # from an existing disk file and then re-save it in the desired form.
  566. #
  567. #    set srcfile "\[ [AEFilename [lindex [winNames -f] 0]] \]"
  568. #    set reply [eval "AEBuild -t 36000 -r \"$name\"" core save {----} [list $srcfile] {dest:} [list $destfile] {fltp:} $saveType ]
  569. #
  570. }
  571.  
  572. #############################################################################
  573. # Quit a running MacPerl app:
  574. proc quitMacperl {} {
  575.     foreach proc [processes] {
  576.         set sig [lindex $proc 1]
  577.         if {$sig == "McPL"} {
  578.             sendQuitEvent [lindex $proc 0]
  579.             # switchTo is necessary to keep MacPerl from blinking
  580.             switchTo [lindex $proc 0]    
  581.         }
  582.     }
  583. }
  584.  
  585. #############################################################################
  586. # Run the selection as a MacPerl script:
  587. # (No special arrangements are made to provide input or capture the output)
  588. proc runTheSelection {} {
  589.     global scriptFile scriptStart
  590.     set scriptFile [lindex [winNames -f] 0]
  591.     set scriptStart [lindex [posToRowCol [getPos]] 0]
  592.     perlExecuteScript [getSelect]
  593. }
  594.  
  595. proc runTheBuffer {} {
  596.     global scriptFile scriptStart
  597.     set scriptFile [lindex [winNames -f] 0]
  598.     set scriptStart 1
  599.     perlExecuteScript [getText 0 [maxPos]]
  600. }
  601.  
  602. proc runAFile {} {
  603.     global scriptFile scriptStart
  604.     if {! [catch {getfile "Select a Perl script"} path]} {
  605.         set scriptFile $path
  606.         set scriptStart 1
  607.         perlExecuteFile $path
  608.     }
  609. }
  610.  
  611. proc saveAndRun {} {
  612.     global scriptFile scriptStart
  613.     save
  614.     set path [lindex [winNames -f] 0]   
  615.     set scriptFile $path
  616.     set scriptStart 1
  617.     perlExecuteFile $path
  618. }
  619.  
  620. #############################################################################
  621. # Run a preattached Perl text-filter script selected from the menu:
  622. #
  623. proc textFiltersProc {menu name} {
  624.     global perlFilters scriptFile scriptStart
  625.     
  626.     perlFileAsFilter $perlFilters($menu:$name)
  627. }
  628.  
  629. #############################################################################
  630. # Reuse the previous (buffer or file) filter:
  631. #
  632. proc repeatLastFilter {} {
  633.     global scriptFile scriptStart perlPrevScript perlMenu PerlmodeVars
  634.     if {$perlPrevScript != {}} {
  635.         set stype [lindex $perlPrevScript 0]
  636.         set name [lindex $perlPrevScript 1]
  637.         if {$stype == "file"} {
  638.             perlFileAsFilter $name
  639.         } elseif {$stype == "buffer"} {
  640.             perlBufferAsFilter $name
  641.         } else {
  642.             message "Bogus filter name : \"$perlPrevScript\""
  643.             set perlPrevScript {}
  644.             set PerlmodeVars(perlLastFilter) $perlPrevScript 
  645.             enableMenuItem $perlMenu repeatLastFilter 0
  646.         }
  647.     }
  648. }
  649.  
  650. #############################################################################
  651. # Ask for a file containing a Perl script to use as a filter:
  652. #
  653. proc selectFileAsFilter {} {
  654.     global scriptFile scriptStart perlPrevScript
  655.     if {! [catch {getfile "Select a MacPerl script"} path]} {
  656.         perlFileAsFilter $path
  657.     }
  658. }
  659.  
  660. #############################################################################
  661. # Ask for an Alpha buffer containing a Perl script to use as a filter:
  662. #
  663. proc selectBufferAsFilter {} {
  664.     global scriptFile scriptStart perlPrevScript
  665.     
  666.     set windows [winNames]
  667.     set current [lindex $windows 0]
  668.     if {[llength $windows] > 1} {
  669.         set name [listpick [lsort $windows]]
  670.         if {[string length $name]} {
  671.             # get the full name of the chosen window
  672.             set wname [lindex [winNames -f] [lsearch -exact $windows $name]]
  673.             perlBufferAsFilter $wname
  674.            }
  675.     }
  676. }
  677.  
  678. #############################################################################
  679. # Open a file from the MacPerl application folder - used by "Open Special"
  680. #
  681. proc perlOpenFile {menu name} {
  682.     set filename [macperlFolder]$name
  683.     if {[file exists $filename]} {
  684.         edit $filename
  685.     } else {
  686.         alertnote "That file doesn't exist yet"
  687.     }
  688. }
  689.  
  690. #############################################################################
  691. # Support procs
  692. #############################################################################
  693.  
  694. #############################################################################
  695. # Prompt the user to enter a string containing command-line args.
  696. #
  697. proc getCmdlineArgs {} {
  698.     global PerlmodeVars
  699.     set oldargs $PerlmodeVars(perlCmdlineArgs)
  700.     if {![catch {prompt "Command-line arguments (if any):" $oldargs} args]} {
  701.         set PerlmodeVars(perlCmdlineArgs) $args
  702.     } else {
  703.         error "getCmdlineArgs: User cancelled"
  704.     }
  705.     return $args
  706. }
  707.  
  708. #############################################################################
  709. # Tell MacPerl to run a script file:
  710. #
  711. proc perlExecuteFile {path {args {}} {flags {}}} {
  712.     global ALPHA macperlPath
  713.     global perlGetOutput perlAutoSwitch perlPromptArgs perlUseDebug
  714.     global scriptFile scriptStart filterHeadLen
  715.     
  716.     if {[string length $path]} {
  717.         set name [checkRunning MacPerl McPL macperlPath 0]
  718.         if {[string length $name]} {
  719.                 
  720.             set ok [regexp {(.*):([^:]*)} $path pathname dirname filename]
  721.             if {!$ok} {    set name $wname    }
  722.  
  723.             if {$path != [scriptPath]} {    
  724.                 set filterHeadLen 0    
  725.             }
  726.             
  727.             if {$perlUseDebug} {
  728.                 append flags "debug"
  729.             }
  730.             if {$perlPromptArgs} { 
  731.                 append args " [getCmdlineArgs]"
  732.             }
  733.             
  734.             sendCloseWinName MacPerl MacPerl
  735.             sendCloseWinName MacPerl "Perl Debug"
  736.             if {$perlAutoSwitch || $perlUseDebug} then {
  737.                 switchTo $name
  738.             } else {
  739.                 message "Running file \"$filename\" as Perl script"
  740.                 watchCursor
  741.             }
  742.             
  743.             perlDoScript "MacPerl" $path $args {} $flags
  744.             
  745. # (not sure which choice is better...)
  746. #            if {!$perlAutoSwitch} then {switchTo $ALPHA}
  747.             switchTo $ALPHA
  748. #
  749.             if {![getMacPerlError]} {
  750.                 if {$perlGetOutput} then {openPerlOutput}
  751.             }
  752.         } else {
  753.             alertnote "Couldn't run MacPerl"
  754.         }
  755.     } else {
  756.         alertnote "No file specified to execute"
  757.     }
  758. }
  759.  
  760. #############################################################################
  761. # Run a MacPerl script, passed explicitly as a string:
  762. #
  763. # If no "#!/bin/perl" line already exists, one is preprended to the script
  764. # by wrapSelectScript, which also sets $filterHeadLen for use by 
  765. # getMacPerlError.
  766. proc perlExecuteScript {script {args ""} {flags {}} } {
  767.     global macperlPath perlGetOutput perlAutoSwitch perlPromptArgs
  768.     global scriptFile scriptStart filterHeadLen perlUseDebug ALPHA
  769.     
  770.     if {$script != ""} {
  771.         set script [wrapSelectScript $script]
  772.         
  773.         if {![regexp {(.*):([^:]*)} $scriptFile pathname dirname filename]} {
  774.             set filename $scriptFile 
  775.         }
  776.  
  777.         set name [checkRunning MacPerl McPL macperlPath 0]
  778.         if {[string length $name]} {
  779.         
  780.             if {$perlUseDebug} {
  781.                 append flags "debug"
  782.             }
  783.             if {$perlPromptArgs} { 
  784.                 append args " [getCmdlineArgs]"
  785.             }
  786.             
  787.             sendCloseWinName MacPerl MacPerl
  788.             sendCloseWinName MacPerl "Perl Debug"
  789.             if {$perlAutoSwitch || $perlUseDebug} then {
  790.                 switchTo $name
  791.             } else {
  792.                 message "Running buffer \"$filename\" as Perl script"
  793.                 watchCursor
  794.             }
  795.             
  796.             perlDoScript "MacPerl" $script $args {} $flags
  797.             
  798.             switchTo $ALPHA
  799.  
  800.             if {![getMacPerlError]} {
  801.                 if {$perlGetOutput} then {openPerlOutput}
  802.             }
  803.         }
  804.         
  805.     } else {
  806.             alertnote "Can't run an empty script"
  807.     }
  808. }
  809.  
  810. #############################################################################
  811. # Prepare the contents of a disk file for use as a text-filter script. 
  812. # (calls perlTextFilter to actually run the script)
  813. proc perlFileAsFilter {path} {
  814.     global scriptFile scriptStart perlPrevScript perlMenu PerlmodeVars
  815.     
  816.     regexp {(.*):([^:]*)} $path pathname dirname name
  817.     
  818.     if {![catch {readFile $path} coreScript]} {
  819.         set script [wrapFilterScript $coreScript]
  820.         set scriptFile $path
  821.         set scriptStart 1
  822.         set perlPrevScript [list "file" $path]
  823.         set PerlmodeVars(perlLastFilter) $perlPrevScript 
  824.         enableMenuItem $perlMenu repeatLastFilter 1
  825.         message "Running file \"$name\" as text filter ..."
  826.         
  827.         perlTextFilter $script
  828.     } else {
  829.         set perlPrevScript {}
  830.         set PerlmodeVars(perlLastFilter) $perlPrevScript 
  831.         enableMenuItem $perlMenu repeatLastFilter 0
  832.         
  833.         alertnote "Couldn't read the script file : $path"
  834.         return
  835.     }
  836. }
  837.  
  838. #############################################################################
  839. # Prepare the contents of a text window for use as a text-filter script. 
  840. # (calls perlTextFilter to actually run the script)
  841. proc perlBufferAsFilter {wname} {
  842.     global scriptFile scriptStart perlPrevScript perlMenu PerlmodeVars
  843.  
  844.     set ok [regexp {(.*):([^:]*)} $wname pathname dirname name]
  845.     if {!$ok} {    set name $wname    }
  846.     
  847.     if {[lsearch [winNames -f] $wname] >= 0} {
  848.         set coreScript [getText -w $wname 0 [maxPos -w $wname]]
  849.         
  850.         # Does it have any text in it?
  851.         if {[string length $coreScript]} {
  852.             set scriptFile $wname
  853.             set scriptStart 1
  854.             set script [wrapFilterScript $coreScript]
  855.             set perlPrevScript [list "buffer" $wname]
  856.             set PerlmodeVars(perlLastFilter) $perlPrevScript 
  857.             enableMenuItem $perlMenu repeatLastFilter 1
  858.             message "Running buffer \"$name\" as text filter ..."
  859.             
  860.             perlTextFilter $script
  861.         }
  862.     } else {
  863.         set perlPrevScript {}
  864.         set PerlmodeVars(perlLastFilter) $perlPrevScript 
  865.         enableMenuItem $perlMenu repeatLastFilter 0
  866.  
  867.         alertnote "Couldn't find buffer : $name"
  868.     }
  869. }
  870.  
  871. #############################################################################
  872. # Run a Perl script as a command-line text filter, arranging for a text
  873. # buffer to be attached as standard input.  The calling routine should already
  874. # have processed the script with wrapFilterScript.  This routine actually
  875. # send the script and takes care of writing the input and reading the output 
  876. # files.
  877. proc perlTextFilter {script {args {}} {flags {}}} {
  878.     global macperlPath perlOverwrite perlUsebuffer perlPromptArgs
  879.     global filterHeadLen scriptFile scriptStart perlUseDebug ALPHA
  880.     global perlOutputWindow perlRecycleOutput
  881.  
  882.     set name [checkRunning MacPerl McPL macperlPath 0]
  883.     if {![string length $name]} {
  884.         alertnote "Couldn't run MacPerl"
  885.         error "Couldn't run MacPerl"
  886.     }
  887.     writeStdin
  888.  
  889.     if {$perlUseDebug} {
  890.         append flags "debug"
  891.     }
  892.     if {$perlPromptArgs} { 
  893.         append args " [getCmdlineArgs]"
  894.     }
  895.     
  896.     sendCloseWinName MacPerl MacPerl
  897.     sendCloseWinName MacPerl "Perl Debug"
  898.     
  899.     if {$perlUseDebug} then {
  900.         switchTo $name
  901.         perlDoScript "MacPerl" [scriptPath] $args [list [stdinPath]] $flags
  902.         set err [getMacPerlError]
  903.  
  904.     } else {
  905.         watchCursor
  906.         set reply [perlDoScriptBatch "MacPerl" [scriptPath] $args [list [stdinPath]]]
  907.         set err [getBatchError $reply]
  908.     }
  909.     
  910.     switchTo $ALPHA
  911.     
  912.     if {$err == 0} {
  913.         if {$perlUseDebug} {
  914.             set outp [sendGetText MacPerl MacPerl]
  915.         } else {
  916. #            set outp [parseReplyOutp $reply]
  917.             set outp [parseReplyResult $reply]
  918.         }
  919.         pasteFilterResult $outp
  920.     }
  921. }
  922.  
  923.  
  924. #############################################################################
  925. # Check the MacPerl output window for error messages.
  926. #
  927. proc getMacPerlError {} {
  928.     
  929.     set diag [getPerlDiag 40]
  930.     set srcs [parseDiagSrcs $diag]
  931.     set errf [parseDiagErrf $diag]
  932.     set mesg [parseDiagMesg $diag]
  933.  
  934.     if {[string length $errf]} {
  935.         showPerlDiag $diag [string length $diag] $mesg $errf $srcs
  936.         gotoPerlError $errf $srcs $mesg
  937.         return 1
  938.         
  939.     } else {
  940.         return 0
  941.     }
  942. }
  943.  
  944. #############################################################################
  945. # Check the MacPerl batch reply for error messages.
  946. #
  947. proc getBatchError {reply} {
  948.     global perlErrorWindow
  949.     
  950.     set fatalError 0
  951.     set diag [parseReplyDiag $reply]
  952.     set errf [parseDiagErrf  $diag ]
  953.     set srcs [parseReplySrcs $reply]
  954.     set mesg [parseDiagMesg  $diag ]
  955.     set errn [parseReplyErrn $reply]
  956.  
  957.     if {$errn} {        
  958.         showPerlDiag $diag $errn $mesg $errf $srcs
  959.         gotoPerlError $errf $srcs $mesg
  960.         set fatalError 1
  961.         
  962.     } elseif {[string length $diag] > 0} {
  963.         showPerlDiag $diag $errn $mesg $errf $srcs
  964.     }
  965.     
  966.     return $fatalError
  967. }
  968.  
  969. #############################################################################
  970. # Display the Perl diagnostic output in its own window.
  971. #
  972. proc showPerlDiag {diag {errn 1} {mesg {}} {errf {}} {srcs {}}} {
  973.         global perlErrorWindow    
  974.         
  975.         set currWin [lindex [winNames] 0]
  976.         if {[lsearch [winNames] $perlErrorWindow] >= 0} {
  977.             bringToFront $perlErrorWindow
  978.             setWinInfo read-only 0
  979.             deleteText 0 [maxPos] 
  980.             insertText $diag
  981.         } else {
  982.             new -n $perlErrorWindow 
  983.              insertText $diag
  984.         }
  985.         
  986.         goto 0
  987.         catch {shrinkWindow 2}
  988.         setWinInfo dirty 0
  989.         setWinInfo read-only 1
  990.         bringToFront $currWin
  991. }
  992.  
  993. #############################################################################
  994. # Bring up a window containing the bug-ridden Perl code and highlight the
  995. # line at which the error was found.
  996. #
  997. proc gotoPerlError {errf srcs {mesg {}}} {
  998.     global scriptFile scriptStart filterHeadLen
  999.  
  1000.     if {$errf == [scriptPath] || $errf == "<AppleEvent>"} {
  1001.         set errf $scriptFile
  1002.         # Convert it to the line number in the original file
  1003.         set srcs [expr $srcs + $scriptStart - $filterHeadLen - 1]
  1004.     }
  1005.     # ... and leave an informative error message
  1006.     #
  1007.     if {[string length $mesg]} {
  1008.         set mesg "$mesg at Line $srcs"            
  1009.     } else {
  1010.         set mesg "MacPerl flagged an error at Line $srcs"    
  1011.     }
  1012.     
  1013.     # Bring up the script file and highlight the flagged line
  1014.     #
  1015.     catch {gotoFileLine $errf $srcs $mesg} fname    
  1016. }
  1017.  
  1018. #############################################################################
  1019. # Read the first block of lines (up to a maximum number) from the MacPerl
  1020. # output window.
  1021. #
  1022. proc getPerlDiag {maxlines} {
  1023.     set pat0 {^[ \t]*$}
  1024.  
  1025.     set lines {}    
  1026.  
  1027.     # read first $maxlines of output to the MacPerl window
  1028.     # (faster, but assumes error message won't appear at 
  1029.     # the end of a lot of output).
  1030.     #
  1031.     set nlines [sendCountLines MacPerl MacPerl]
  1032.     set nlines [expr ($nlines > $maxlines)?$maxlines:$nlines]
  1033.     if {$nlines > 0} {
  1034.         set output [sendGetText MacPerl MacPerl 1 $nlines]
  1035.         
  1036.         foreach line [split $output "\r"] {
  1037.             if  {[regexp $pat0 $line mtch]} {
  1038.                 break
  1039.             } else {
  1040.                 append lines "$line\n"
  1041.             }
  1042.         }
  1043.     }
  1044.     return $lines
  1045. }
  1046.  
  1047. #############################################################################
  1048. # Extract various items out of the MacPerl diagnostic output
  1049. #
  1050.  
  1051. # Name of the file in which the error was found
  1052. #
  1053. proc parseDiagErrf {diag}    {
  1054.     if {![regexp {File '([^']+)'; Line} $diag allofit errf]} { 
  1055.         set errf {}
  1056.     }
  1057.     return $errf
  1058. }
  1059.  
  1060. # The line number on which the error was found
  1061. #
  1062. proc parseDiagSrcs {diag}    {
  1063.     if {![regexp {File '[^']+'; Line ([0-9]+)} $diag allofit srcs]} { 
  1064.         set srcs 0 
  1065.     }
  1066.     return $srcs
  1067. }
  1068.  
  1069. # The error message associated with error
  1070. #
  1071. proc parseDiagMesg {diag} {
  1072.     set pat1 {^#(.*)$}
  1073.     set pat2 {File '([^']+)'; Line ([0-9]+)}
  1074.     
  1075.     set errMessage {}
  1076.     set errFound 0
  1077.     
  1078.     foreach line [split $diag "\n"] {
  1079.         if {[regexp $pat2 $line mtch num]} {
  1080.             set errFound 1
  1081.         } elseif {[regexp $pat1 $line mtch err]} {
  1082.             if {$errFound == 0} {
  1083.                 set errMessage $err
  1084.             }
  1085.         }
  1086.     }
  1087.     return $errMessage
  1088. }
  1089.  
  1090. #############################################################################
  1091. # Extract various return parameters out of a MacPerl DoScript reply
  1092. #
  1093.  
  1094. # Result from batch script
  1095. #
  1096. proc parseReplyResult {reply} {
  1097.     if {![regexp {'?\-\-\-\-'?:╥([^╙]*)╙} $reply allofit result]} { 
  1098.         set result {}
  1099.     }
  1100.     return $result
  1101. }
  1102.  
  1103. # Standard output of batch script
  1104. #
  1105. proc parseReplyOutp {reply} {
  1106.     if {![regexp {OUTP:╥([^╙]*)╙} $reply allofit outp]} { 
  1107.         set outp {}
  1108.     }
  1109.     return $outp
  1110. }
  1111.  
  1112. # Diagnostic output of the batch script
  1113. #
  1114. proc parseReplyDiag {reply}    {
  1115.     if {[regexp {diag:╥([^╙]*)╙} $reply allofit diag]}  {
  1116.     } else { 
  1117.         set diag {}
  1118.     }
  1119.     return $diag
  1120. }
  1121.  
  1122. # File alias of the script file in which the error was found
  1123. #
  1124. proc parseReplyErob {reply}    {
  1125.     if {![regexp {erob:alis\(╟(.*)╚\)} $reply allofit erob]} {
  1126.         set erob {} 
  1127.     }
  1128.     return $erob
  1129. }
  1130.  
  1131. # First line flagged in error
  1132. #
  1133. proc parseReplySrcs {reply}    {
  1134.     if {![regexp {erng:{srcs:([0-9]+)[^\}]*}} $reply allofit srcs]} { 
  1135.         set srcs 0 
  1136.     }
  1137.     return $srcs
  1138. }
  1139.  
  1140. # Last line flagged in error
  1141. #
  1142. proc parseReplySrce {reply}    {
  1143.     if {![regexp {erng:{[^\}]*srce:([0-9]+)}} $reply allofit srce]} { 
  1144.         set srce 0
  1145.     }
  1146.     return $srce
  1147. }
  1148.  
  1149. # Error number
  1150. #
  1151. proc parseReplyErrn {reply}    {
  1152.     if {![regexp {errn:([0-9]+)} $reply allofit errn]} {
  1153.         set errn 0
  1154.     }
  1155.     return $errn
  1156. }
  1157.  
  1158. #############################################################################
  1159. #  Take a Perl script and add commands to take the file STDIN as standard
  1160. #  input and STDOUT as standard output.  This allows scripts written as
  1161. #  Unix command-line filters to be used in the (non-MPW) Mac environment as
  1162. #  text filters.
  1163. #
  1164. #  If there's already a #! line in the script, then the new commands
  1165. #  are added after that line.  If there was no #! line in the first place,
  1166. #  one is added, in case MacPerl is set up to require it (can't hurt...) 
  1167. #
  1168. #  $filterHeadLen counts the number of lines we add to the top of the
  1169. #  original script, so that we can allow for it in interpreting error
  1170. #  messages issued by MacPerl.
  1171. #
  1172. #  *** As of MacPerl 4.1.4, this business is pretty much obsolete ***
  1173. #
  1174. proc wrapFilterScript {coreScript} {
  1175.     global filterHeadLen
  1176.  
  1177.     if {[regexp -indices {(#![     !-~]*)} $coreScript allofit cmdln]} {
  1178.         set endPos [lindex $cmdln 1]
  1179.         set filterHead [string range $coreScript 0 [expr $endPos+1]]
  1180.         set coreScript [string range $coreScript [expr $endPos+2] end]
  1181.         set filterHeadLen 0
  1182.     } else {
  1183.         set filterHead "#!/bin/perl\n\r"
  1184.         set filterHeadLen 2
  1185.     }
  1186.         
  1187.     set script $filterHead
  1188.     append script $coreScript
  1189.     
  1190.     # for debugging purposes, save the script on disk
  1191.     #
  1192.     writeScript $script
  1193.     return $script
  1194. }        
  1195.  
  1196. #############################################################################
  1197. #  Add a #!/bin/perl line to the script if it doesn't contain one already.
  1198. #  (MacPerl puts up dialog if this line is missing when it expects it,
  1199. #  hanging the DoScript and leaving us stuck.)
  1200. #
  1201. proc wrapSelectScript {coreScript} {
  1202.     global filterHeadLen
  1203.  
  1204.     if {![regexp -indices {(#![     !-~]*)} $coreScript allofit cmdln]} {
  1205.         set script "#!/bin/perl\r\n"
  1206.         append script $coreScript
  1207.         set filterHeadLen 1
  1208.     } else {
  1209.         set script $coreScript
  1210.         set filterHeadLen 0
  1211.     }
  1212.     
  1213.     # for debugging purposes, save the script on disk
  1214.     #
  1215.     writeScript $script
  1216.     return $script
  1217. }        
  1218.  
  1219. #############################################################################
  1220. #  Paste result of the filter operation in place of the input text, or in
  1221. #  a new window (depending on the flag $perlOverwrite
  1222. #
  1223. proc pasteFilterResult {text} {
  1224.     global perlOverwrite perlRecycleOutput perlOutputWindow
  1225.     global perlUsebuffer 
  1226.     
  1227.     if {!$perlOverwrite} {
  1228.         if {$perlRecycleOutput && 
  1229.             [lsearch [winNames] $perlOutputWindow] >= 0} {                
  1230.             bringToFront $perlOutputWindow
  1231.         } else {
  1232.             new -n $perlOutputWindow
  1233.         }
  1234.     }
  1235.     
  1236.     if {$perlUsebuffer || $perlRecycleOutput} {
  1237.         set from 0
  1238.         set to [maxPos]
  1239.     } else {
  1240.         set from [getPos] 
  1241.         set to [selEnd]
  1242.     }    
  1243.     replaceText $from $to $text
  1244.     
  1245.     if {!$perlOverwrite || $perlUseBuffer} {
  1246.         catch {shrinkWindow 2}
  1247.         goto 0
  1248.     } else {
  1249.         catch shrinkWindow
  1250.         goto $from
  1251.     }
  1252.     if {!$perlOverwrite} { setWinInfo dirty 0 }
  1253. }    
  1254.  
  1255. #############################################################################
  1256. #  Extend the current selection to encompass complete lines.  If the 
  1257. #  'applyToBuffer' flag is checked, then the entire buffer is selected.
  1258. #
  1259. proc completeSelection {} {
  1260.     global perlUsebuffer filterInput
  1261.     set filterInput "buffer \"[lindex [winNames] 0]\""
  1262.     if {$perlUsebuffer} {
  1263.         set start 0
  1264.         set end [maxPos]
  1265.     } else {
  1266.         set start [lineStart [getPos]]
  1267.         set end [nextLineStart [expr [selEnd]-1]]
  1268.         if {$end == $start} { set end [nextLineStart [selEnd]] }
  1269.         
  1270.         set startLine [lindex [posToRowCol $start] 0]
  1271.         set endLine [expr [lindex [posToRowCol $end] 0] - 1]
  1272.         if {$endLine > $startLine+1} {
  1273.             set filterInput "lines $startLine to $endLine of $filterInput"
  1274.         } else {
  1275.             set filterInput "line $startLine of $filterInput"
  1276.         }
  1277.    }
  1278.     return [list $start $end]
  1279. }
  1280.  
  1281. #############################################################################
  1282. #  writeStdin: Extend the selection, as appropriate, and write it to the 
  1283. #     STDIN file in the MacPerl directory.
  1284. #
  1285. #  writeScript: Write the SCRIPT file in the MacPerl directory.  MacPerl will
  1286. #     read the script from this file. 
  1287. #
  1288. proc writeStdin {} {
  1289.     set res [completeSelection]
  1290.     set tmpfid [open [stdinPath] "w+"]
  1291.     puts $tmpfid [eval getText $res]
  1292.     close $tmpfid
  1293. }
  1294.  
  1295. # This is unnecessary now, but maybe it'll still useful to save the script
  1296. # file for debugging.
  1297. #
  1298. proc writeScript {script} {
  1299.     set tmpfid [open [scriptPath] "w+"]
  1300.     puts $tmpfid $script 
  1301.     close $tmpfid
  1302. }
  1303.  
  1304. #############################################################################
  1305. # Read the MacPerl output window and load the contents, if any, into
  1306. # a new Alpha window. 
  1307. #
  1308. proc openPerlOutput {} {
  1309.     global perlRecycleOutput perlOutputWindow
  1310.     
  1311.     set output [sendGetText MacPerl MacPerl]
  1312.     if {[string length $output]} {
  1313.         if {$perlRecycleOutput && 
  1314.             [lsearch [winNames] $perlOutputWindow] >= 0} {
  1315.             
  1316.             bringToFront $perlOutputWindow
  1317.             replaceText 0 [maxPos] $output
  1318.         } else {
  1319.             new -n $perlOutputWindow
  1320.             insertText $output
  1321.         }
  1322.         catch {shrinkWindow 2}
  1323.         setWinInfo dirty 0
  1324.         goto 0
  1325.     }
  1326. }
  1327.  
  1328. #############################################################################
  1329. # translate special DoScript flags into flags string $usrf
  1330. #
  1331. proc perlScriptFlags {{flags {}}} {
  1332.      set usrf {}
  1333.  
  1334.     if {[lsearch -exact $flags "extract"] >= 0} {
  1335.         append usrf { "EXTR" 'true'}
  1336.     } elseif {[lsearch -exact $flags "noextract"] >= 0} {
  1337.         append usrf { "EXTR" 'fals'}
  1338.     }        
  1339.     if {[lsearch -exact $flags "debug"] >= 0} {
  1340.         append usrf { "DEBG" 'true'}
  1341.     } elseif {[lsearch -exact $flags "nodebug"] >= 0} {
  1342.         append usrf { "DEBG" 'fals'}
  1343.     }        
  1344.  
  1345.     if {[lsearch -exact $flags "local"] >= 0} {
  1346.         append usrf { "MODE" 'LOCL'}
  1347.     } elseif {[lsearch -exact $flags "batch"] >= 0} {
  1348.         append usrf { "MODE" 'BATC'}
  1349.     } elseif {[lsearch -exact $flags "remote"] >= 0} {
  1350.         append usrf { "MODE" 'RCTL'}
  1351.     }        
  1352.     return $usrf
  1353.  
  1354. proc perlScriptArgs {{args {}} {fileargs {}}} {
  1355.     set nargs 0
  1356.     set argv {}
  1357.     
  1358.     foreach item [parseWords $args] {
  1359.         set item [string trim $item]
  1360.         if {[string length $item]} {
  1361.             append argv ", [curlyq $item]"
  1362.             incr nargs
  1363.         }
  1364.     }
  1365.     foreach filename $fileargs {
  1366.         set item [string trim $filename]
  1367.         if {[string length $item]} {
  1368.             append argv ", [curlyq $item]"
  1369.             incr nargs
  1370.         }
  1371.     }
  1372.     return $argv
  1373. }
  1374.  
  1375. #############################################################################
  1376. # General Apple Event routines
  1377. # (most of these have been moved to SystemCode:appleEvents.tcl)
  1378. #
  1379. # DoScript for MacPerl 4.1.3
  1380. # (runs in "Local" mode under v4.1.4+)
  1381. #
  1382. proc perlDoScript {appname script {args {}} {fileargs {}} {flags {}} } {
  1383.     # form list of quoted "command-line" args
  1384.     #
  1385.     if {$script != ""} {
  1386.         set argv "\[[curlyq [string trim $script]]"
  1387. #         foreach item [split [join $args " "] " "] {
  1388. #}
  1389.         append argv [perlScriptArgs $args $fileargs]
  1390.         append argv "]"
  1391.         
  1392.         set usrf [perlScriptFlags $flags]
  1393.         set reply [eval "AEBuild -t 36000 -r \"$appname\" misc dosc $usrf \"----\" [list $argv] "]
  1394.     #    alertnote $reply
  1395.     }
  1396. }
  1397.  
  1398. # DoScript for MacPerl 4.1.4+
  1399. #
  1400. proc perlDoScriptBatch {appname script {args {}} {fileargs {}}} {
  1401.     
  1402.     # form list of quoted "command-line" args
  1403.     #
  1404.     if {$script != ""} {
  1405.         set argv "\[[curlyq [string trim $script]]"
  1406.         append argv [perlScriptArgs $args $fileargs ] 
  1407.         append argv "]"
  1408.                 
  1409.         set reply [eval "AEBuild -t 36000 -r \"$appname\" misc dosc MODE BATC \"----\" [list $argv]"]
  1410.         
  1411. #         perlDisplayReply $reply
  1412.  
  1413.     } else {
  1414.         set reply {}
  1415.     }
  1416.     return $reply
  1417. }
  1418.  
  1419. # For debugging 
  1420. #
  1421. proc perlDisplayReply {reply} {
  1422.     set currWin [lindex [winNames] 0]
  1423.     new -n {*** DoScript Reply **} 
  1424.     insertText $reply
  1425.         
  1426.     goto 0
  1427.     catch {shrinkWindow 2}
  1428.     setWinInfo dirty 0
  1429.     setWinInfo read-only 1
  1430.     bringToFront $currWin
  1431. }
  1432.  
  1433. # DoScript to launch interactive debugger (for MacPerl 4.1.4+)
  1434. #
  1435. proc perlDoScriptDebug {appname script {args {}} {fileargs {}}} {
  1436.     
  1437.     # form list of quoted "command-line" args
  1438.     #
  1439.     if {$script != ""} {
  1440.         set argv "\[[curlyq [string trim $script]]"
  1441.         append argv [perlScriptArgs "$args debug" $fileargs ] 
  1442.         append argv "]"
  1443.                 
  1444.         set reply [eval "AEBuild -t 36000 -r \"$appname\" misc dosc MODE RCTL \"----\" [list $argv]"]
  1445.  
  1446.         new -n {** DoScriptDebug Reply **} 
  1447.         insertText $reply
  1448.             
  1449.         goto 0
  1450.         catch {shrinkWindow 2}
  1451.         setWinInfo dirty 0
  1452.         setWinInfo read-only 1
  1453.  
  1454.  
  1455.     } else {
  1456.         set reply {}
  1457.     }
  1458.     return $reply
  1459. }
  1460.  
  1461. ##############################################################################
  1462. # Automatic indexing of Perl subs
  1463. #
  1464. proc PerlMarkFile {} {
  1465.     set end [maxPos]
  1466.     set pos 0
  1467.     set l {}
  1468.     while {![catch {search -f 1 -r 1 -m 0 -i 0 {^sub} $pos} res]} {
  1469.         set start [lindex $res 0]
  1470.         set end [nextLineStart $start]
  1471.         set text [lindex [getText $start $end] 1]
  1472.         set pos $end
  1473.         set inds($text) [lineStart [expr $start - 1]]
  1474.     }
  1475.  
  1476.     if {[info exists inds]} {
  1477.         foreach f [lsort [array names inds]] {
  1478.             set next [nextLineStart $inds($f)]
  1479.             setNamedMark $f $inds($f) $next $next
  1480.         }
  1481.     }
  1482. }
  1483.  
  1484.  
  1485. # Open a 'require'd Perl file.
  1486. proc perlFindRequire {from {to 0}} {
  1487.     set reqPat {^[     ]*require[     ]*(\"[^\"]+\"|\'[^\']+\'|[^     ]+)}
  1488.     if {$to == 0} { set to $from }
  1489.     set beg [lineStart $from]
  1490.     set end [nextLineStart $to]
  1491.     set words [parseWords [getText $beg $end]]
  1492.     if {[string tolower [lindex $words 0]] != "require"} {
  1493.         error "Not a require statement"
  1494.     }
  1495.     set root [string trim [lindex $words 1] {'"}]
  1496.     return $root
  1497. }
  1498.  
  1499. proc inlineRequires {} {
  1500.     global lastMatchingLines
  1501.     
  1502.     set reqPat {^[     ]*require[     ]*(\"[^\"]+\"|\'[^\']+\'|[^     ]+)}
  1503.     set pos 0
  1504.     while {![catch {search -s -f 1 -r 1 -m 0 -i 1 $reqPat $pos} mtch]} {
  1505.          [lindex [posToRowCol [lindex $mtch 0]] 0]] 
  1506.         set name [string [eval getText $mtch]
  1507.         set pos [lindex $mtch 1]
  1508.         incr matches
  1509.     }
  1510. }
  1511.  
  1512. # Open a Perl source file. 
  1513. #
  1514. proc openPerlFile {file {extensions {""}}} {
  1515.     global perlSearchPath
  1516.     # Determine absolute file specification
  1517.     # Ignore $extensions if $file already has an extension
  1518.     if {[string length [file extension $file]] == 0} {
  1519.         set extensions {""}
  1520.     }
  1521.     foreach ext $extensions {
  1522.         set filename [absolutePath $file$ext]
  1523.         if {![catch {openFileQuietly $filename}]} {
  1524.             message $filename
  1525.             return 
  1526.         }
  1527.     }
  1528.     if {[llength $perlSearchPath] == 0} { buildPerlSearchPath }
  1529.     foreach folder $perlSearchPath {
  1530.         foreach ext $extensions {
  1531.             set filename "$folder$file$ext"
  1532.             if {![catch {openFileQuietly $filename}]} {
  1533.                 message $filename
  1534.                 return     
  1535.             }
  1536.         }
  1537.     }
  1538.     beep
  1539.     message "can't find Perl source file \"$file\""
  1540. }
  1541.  
  1542. # Return a list of folders in which to search for Perl library files, 
  1543. # including the lib folder in the Perl application directory and the
  1544. # $perlLib folder (if it exists) .  
  1545. # The current folder is not included in the list.
  1546. #
  1547. # (The $perlLib folder is assigned from the AppPaths submenu.)
  1548. #
  1549. proc buildPerlSearchPath {} {
  1550.     global perlLib macperlPath perlSearchPath
  1551.     message "building Perl search path..."
  1552.     set folders {}
  1553.     
  1554.     # The local lib folder:
  1555.     if {[info exists perlLib] && [string length $perlLib] > 0} { 
  1556.         set folders [concat $folders [list $perlLib]]
  1557.         # Search subfolders one level deep:
  1558.         set folders [concat $folders [listSubfolders $perlLib 1]]
  1559.     }
  1560.  
  1561.     # Any "*lib*" folders in the MacPerl application folder:
  1562.     if {[info exists macperlPath] && [string length $macperlPath] > 0} { 
  1563.         set appDir [file dirname $macperlPath]
  1564.         set folders [concat $folders [list $appDir]]
  1565.         # Bug:  'glob' is case sensitive!
  1566.         foreach folder [glob "$appDir:*\[Ll\]ib*"] {
  1567.             set folders [concat $folders [list $folder]]
  1568.             # Search subfolders one level deep:
  1569.             set folders [concat $folders [listSubfolders $folder 1]]
  1570.         }
  1571.     }
  1572.  
  1573.     # Make sure each folder ends with a colon
  1574.     set perlSearchPath {}
  1575.     foreach folder $folders {
  1576.         set folder "[string trimright $folder {:}]:"
  1577.         set perlSearchPath [concat $perlSearchPath [list $folder]]
  1578.     }
  1579. }
  1580.  
  1581. ###########################################################################
  1582.  
  1583.  
  1584.